{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Implementing A Logistic Regression Model from Scratch with PyTorch\n",
    "\n",
    "![alt text](https://drive.google.com/uc?export=view&id=11Bv3uhZtVgRVYVWDl9_ZAYQ0GU36LhM9)\n",
    "\n",
    "\n",
    "In this tutorial, we are going to implement a logistic regression model from scratch with PyTorch. The model will be designed with neural networks in mind and will be used for a simple image classification task. I believe this is a great approach to begin understanding the fundamental building blocks behind a neural network. Additionally, we will also look at best practices on how to use PyTorch for training neural networks.\n",
    "\n",
    "After completing this tutorial the learner is expected to know the basic building blocks of a logistic regression model. The learner is also expected to apply the logistic regression model to a binary image classification problem of their choice using PyTorch code.\n",
    "\n",
    "---\n",
    "\n",
    "**Author:** Elvis Saravia ( [Twitter](https://twitter.com/omarsar0) | [LinkedIn](https://www.linkedin.com/in/omarsar/))\n",
    "\n",
    "**Complete Code Walkthrough:** [Blog post](https://medium.com/dair-ai/implementing-a-logistic-regression-model-from-scratch-with-pytorch-24ea062cd856?source=friends_link&sk=49dcddb17d1d021d2d677f3666c88463)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Import the usual libraries\n",
    "import torch\n",
    "import torchvision\n",
    "import torch.nn as nn\n",
    "from torchvision import datasets, models, transforms\n",
    "import os\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "## configuration to detect cuda or cpu\n",
    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
    "print (device)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Importing Dataset\n",
    "In this tutorial we will be working on an image classification problem. You can find the public dataset [here](https://download.pytorch.org/tutorial/hymenoptera_data.zip). \n",
    "\n",
    "The objective of our model is to learn to classify between \"bee\" vs. \"no bee\" images.\n",
    "\n",
    "Uncomment the code below to download and unzip the data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2022-06-17 23:55:52--  https://download.pytorch.org/tutorial/hymenoptera_data.zip\n",
      "Resolving download.pytorch.org (download.pytorch.org)... 18.67.65.73, 18.67.65.42, 18.67.65.118, ...\n",
      "Connecting to download.pytorch.org (download.pytorch.org)|18.67.65.73|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 47286322 (45M) [application/zip]\n",
      "Saving to: ‘hymenoptera_data.zip’\n",
      "\n",
      "hymenoptera_data.zi 100%[===================>]  45.10M   152MB/s    in 0.3s    \n",
      "\n",
      "2022-06-17 23:55:53 (152 MB/s) - ‘hymenoptera_data.zip’ saved [47286322/47286322]\n",
      "\n",
      "Archive:  hymenoptera_data.zip\n",
      "   creating: hymenoptera_data/\n",
      "   creating: hymenoptera_data/train/\n",
      "   creating: hymenoptera_data/train/ants/\n",
      "  inflating: hymenoptera_data/train/ants/0013035.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1030023514_aad5c608f9.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1095476100_3906d8afde.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1099452230_d1949d3250.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/116570827_e9c126745d.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1225872729_6f0856588f.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1262877379_64fcada201.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1269756697_0bce92cdab.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1286984635_5119e80de1.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/132478121_2a430adea2.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1360291657_dc248c5eea.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1368913450_e146e2fb6d.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1473187633_63ccaacea6.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/148715752_302c84f5a4.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1489674356_09d48dde0a.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/149244013_c529578289.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/150801003_3390b73135.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/150801171_cd86f17ed8.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/154124431_65460430f2.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/162603798_40b51f1654.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1660097129_384bf54490.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/167890289_dd5ba923f3.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1693954099_46d4c20605.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/175998972.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/178538489_bec7649292.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1804095607_0341701e1c.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1808777855_2a895621d7.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/188552436_605cc9b36b.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1917341202_d00a7f9af5.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/1924473702_daa9aacdbe.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/196057951_63bf063b92.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/196757565_326437f5fe.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/201558278_fe4caecc76.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/201790779_527f4c0168.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/2019439677_2db655d361.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/207947948_3ab29d7207.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/20935278_9190345f6b.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/224655713_3956f7d39a.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/2265824718_2c96f485da.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/2265825502_fff99cfd2d.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/226951206_d6bf946504.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/2278278459_6b99605e50.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/2288450226_a6e96e8fdf.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/2288481644_83ff7e4572.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/2292213964_ca51ce4bef.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/24335309_c5ea483bb8.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/245647475_9523dfd13e.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/255434217_1b2b3fe0a4.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/258217966_d9d90d18d3.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/275429470_b2d7d9290b.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/28847243_e79fe052cd.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/318052216_84dff3f98a.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/334167043_cbd1adaeb9.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/339670531_94b75ae47a.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/342438950_a3da61deab.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/36439863_0bec9f554f.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/374435068_7eee412ec4.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/382971067_0bfd33afe0.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/384191229_5779cf591b.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/386190770_672743c9a7.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/392382602_1b7bed32fa.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/403746349_71384f5b58.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/408393566_b5b694119b.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/424119020_6d57481dab.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/424873399_47658a91fb.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/450057712_771b3bfc91.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/45472593_bfd624f8dc.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/459694881_ac657d3187.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/460372577_f2f6a8c9fc.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/460874319_0a45ab4d05.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/466430434_4000737de9.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/470127037_513711fd21.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/474806473_ca6caab245.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/475961153_b8c13fd405.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/484293231_e53cfc0c89.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/49375974_e28ba6f17e.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/506249802_207cd979b4.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/506249836_717b73f540.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/512164029_c0a66b8498.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/512863248_43c8ce579b.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/518773929_734dbc5ff4.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/522163566_fec115ca66.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/522415432_2218f34bf8.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/531979952_bde12b3bc0.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/533848102_70a85ad6dd.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/535522953_308353a07c.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/540889389_48bb588b21.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/541630764_dbd285d63c.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/543417860_b14237f569.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/560966032_988f4d7bc4.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/5650366_e22b7e1065.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/6240329_72c01e663e.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/6240338_93729615ec.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/649026570_e58656104b.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/662541407_ff8db781e7.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/67270775_e9fdf77e9d.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/6743948_2b8c096dda.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/684133190_35b62c0c1d.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/69639610_95e0de17aa.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/707895295_009cf23188.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/7759525_1363d24e88.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/795000156_a9900a4a71.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/822537660_caf4ba5514.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/82852639_52b7f7f5e3.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/841049277_b28e58ad05.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/886401651_f878e888cd.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/892108839_f1aad4ca46.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/938946700_ca1c669085.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/957233405_25c1d1187b.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/9715481_b3cb4114ff.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/998118368_6ac1d91f81.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/ant photos.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/Ant_1.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/army-ants-red-picture.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/formica.jpeg  \n",
      "  inflating: hymenoptera_data/train/ants/hormiga_co_por.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/imageNotFound.gif  \n",
      "  inflating: hymenoptera_data/train/ants/kurokusa.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/MehdiabadiAnt2_600.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/Nepenthes_rafflesiana_ant.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/swiss-army-ant.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/termite-vs-ant.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/trap-jaw-ant-insect-bg.jpg  \n",
      "  inflating: hymenoptera_data/train/ants/VietnameseAntMimicSpider.jpg  \n",
      "   creating: hymenoptera_data/train/bees/\n",
      "  inflating: hymenoptera_data/train/bees/1092977343_cb42b38d62.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/1093831624_fb5fbe2308.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/1097045929_1753d1c765.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/1232245714_f862fbe385.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/129236073_0985e91c7d.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/1295655112_7813f37d21.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/132511197_0b86ad0fff.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/132826773_dbbcb117b9.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/150013791_969d9a968b.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/1508176360_2972117c9d.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/154600396_53e1252e52.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/16838648_415acd9e3f.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/1691282715_0addfdf5e8.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/17209602_fe5a5a746f.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/174142798_e5ad6d76e0.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/1799726602_8580867f71.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/1807583459_4fe92b3133.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/196430254_46bd129ae7.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/196658222_3fffd79c67.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/198508668_97d818b6c4.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2031225713_50ed499635.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2037437624_2d7bce461f.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2053200300_8911ef438a.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/205835650_e6f2614bee.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/208702903_42fb4d9748.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/21399619_3e61e5bb6f.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2227611847_ec72d40403.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2321139806_d73d899e66.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2330918208_8074770c20.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2345177635_caf07159b3.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2358061370_9daabbd9ac.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2364597044_3c3e3fc391.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2384149906_2cd8b0b699.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2397446847_04ef3cd3e1.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2405441001_b06c36fa72.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2445215254_51698ff797.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2452236943_255bfd9e58.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2467959963_a7831e9ff0.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2470492904_837e97800d.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2477324698_3d4b1b1cab.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2477349551_e75c97cf4d.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2486729079_62df0920be.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2486746709_c43cec0e42.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2493379287_4100e1dacc.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2495722465_879acf9d85.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2528444139_fa728b0f5b.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2538361678_9da84b77e3.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2551813042_8a070aeb2b.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2580598377_a4caecdb54.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2601176055_8464e6aa71.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2610833167_79bf0bcae5.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2610838525_fe8e3cae47.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2617161745_fa3ebe85b4.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2625499656_e3415e374d.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2634617358_f32fd16bea.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2638074627_6b3ae746a0.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2645107662_b73a8595cc.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2651621464_a2fa8722eb.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2652877533_a564830cbf.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/266644509_d30bb16a1b.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2683605182_9d2a0c66cf.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2704348794_eb5d5178c2.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2707440199_cd170bd512.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2710368626_cb42882dc8.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2722592222_258d473e17.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2728759455_ce9bb8cd7a.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2756397428_1d82a08807.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2765347790_da6cf6cb40.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2781170484_5d61835d63.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/279113587_b4843db199.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2792000093_e8ae0718cf.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2801728106_833798c909.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2822388965_f6dca2a275.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2861002136_52c7c6f708.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2908916142_a7ac8b57a8.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/29494643_e3410f0d37.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2959730355_416a18c63c.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/2962405283_22718d9617.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/3006264892_30e9cced70.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/3030189811_01d095b793.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/3030772428_8578335616.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/3044402684_3853071a87.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/3074585407_9854eb3153.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/3079610310_ac2d0ae7bc.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/3090975720_71f12e6de4.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/3100226504_c0d4f1e3f1.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/342758693_c56b89b6b6.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/354167719_22dca13752.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/359928878_b3b418c728.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/365759866_b15700c59b.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/36900412_92b81831ad.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/39672681_1302d204d1.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/39747887_42df2855ee.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/421515404_e87569fd8b.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/444532809_9e931e2279.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/446296270_d9e8b93ecf.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/452462677_7be43af8ff.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/452462695_40a4e5b559.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/457457145_5f86eb7e9c.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/465133211_80e0c27f60.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/469333327_358ba8fe8a.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/472288710_2abee16fa0.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/473618094_8ffdcab215.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/476347960_52edd72b06.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/478701318_bbd5e557b8.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/507288830_f46e8d4cb2.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/509247772_2db2d01374.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/513545352_fd3e7c7c5d.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/522104315_5d3cb2758e.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/537309131_532bfa59ea.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/586041248_3032e277a9.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/760526046_547e8b381f.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/760568592_45a52c847f.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/774440991_63a4aa0cbe.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/85112639_6e860b0469.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/873076652_eb098dab2d.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/90179376_abc234e5f4.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/92663402_37f379e57a.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/95238259_98470c5b10.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/969455125_58c797ef17.jpg  \n",
      "  inflating: hymenoptera_data/train/bees/98391118_bdb1e80cce.jpg  \n",
      "   creating: hymenoptera_data/val/\n",
      "   creating: hymenoptera_data/val/ants/\n",
      "  inflating: hymenoptera_data/val/ants/10308379_1b6c72e180.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1053149811_f62a3410d3.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1073564163_225a64f170.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1119630822_cd325ea21a.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1124525276_816a07c17f.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/11381045_b352a47d8c.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/119785936_dd428e40c3.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1247887232_edcb61246c.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1262751255_c56c042b7b.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1337725712_2eb53cd742.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1358854066_5ad8015f7f.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1440002809_b268d9a66a.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/147542264_79506478c2.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/152286280_411648ec27.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/153320619_2aeb5fa0ee.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/153783656_85f9c3ac70.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/157401988_d0564a9d02.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/159515240_d5981e20d1.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/161076144_124db762d6.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/161292361_c16e0bf57a.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/170652283_ecdaff5d1a.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/17081114_79b9a27724.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/172772109_d0a8e15fb0.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/1743840368_b5ccda82b7.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/181942028_961261ef48.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/183260961_64ab754c97.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/2039585088_c6f47c592e.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/205398178_c395c5e460.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/208072188_f293096296.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/209615353_eeb38ba204.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/2104709400_8831b4fc6f.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/212100470_b485e7b7b9.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/2127908701_d49dc83c97.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/2191997003_379df31291.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/2211974567_ee4606b493.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/2219621907_47bc7cc6b0.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/2238242353_52c82441df.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/2255445811_dabcdf7258.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/239161491_86ac23b0a3.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/263615709_cfb28f6b8e.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/308196310_1db5ffa01b.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/319494379_648fb5a1c6.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/35558229_1fa4608a7a.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/412436937_4c2378efc2.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/436944325_d4925a38c7.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/445356866_6cb3289067.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/459442412_412fecf3fe.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/470127071_8b8ee2bd74.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/477437164_bc3e6e594a.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/488272201_c5aa281348.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/502717153_3e4865621a.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/518746016_bcc28f8b5b.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/540543309_ddbb193ee5.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/562589509_7e55469b97.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/57264437_a19006872f.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/573151833_ebbc274b77.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/649407494_9b6bc4949f.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/751649788_78dd7d16ce.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/768870506_8f115d3d37.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/800px-Meat_eater_ant_qeen_excavating_hole.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/8124241_36b290d372.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/8398478_50ef10c47a.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/854534770_31f6156383.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/892676922_4ab37dce07.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/94999827_36895faade.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/Ant-1818.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/ants-devouring-remains-of-large-dead-insect-on-red-tile-in-Stellenbosch-South-Africa-closeup-1-DHD.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/desert_ant.jpg  \n",
      "  inflating: hymenoptera_data/val/ants/F.pergan.28(f).jpg  \n",
      "  inflating: hymenoptera_data/val/ants/Hormiga.jpg  \n",
      "   creating: hymenoptera_data/val/bees/\n",
      "  inflating: hymenoptera_data/val/bees/1032546534_06907fe3b3.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/10870992_eebeeb3a12.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/1181173278_23c36fac71.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/1297972485_33266a18d9.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/1328423762_f7a88a8451.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/1355974687_1341c1face.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/144098310_a4176fd54d.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/1486120850_490388f84b.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/149973093_da3c446268.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/151594775_ee7dc17b60.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/151603988_2c6f7d14c7.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/1519368889_4270261ee3.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/152789693_220b003452.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/177677657_a38c97e572.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/1799729694_0c40101071.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/181171681_c5a1a82ded.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/187130242_4593a4c610.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/203868383_0fcbb48278.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2060668999_e11edb10d0.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2086294791_6f3789d8a6.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2103637821_8d26ee6b90.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2104135106_a65eede1de.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/215512424_687e1e0821.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2173503984_9c6aaaa7e2.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/220376539_20567395d8.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/224841383_d050f5f510.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2321144482_f3785ba7b2.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/238161922_55fa9a76ae.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2407809945_fb525ef54d.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2415414155_1916f03b42.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2438480600_40a1249879.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2444778727_4b781ac424.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2457841282_7867f16639.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2470492902_3572c90f75.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2478216347_535c8fe6d7.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2501530886_e20952b97d.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2506114833_90a41c5267.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2509402554_31821cb0b6.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2525379273_dcb26a516d.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/26589803_5ba7000313.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2668391343_45e272cd07.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2670536155_c170f49cd0.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2685605303_9eed79d59d.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2702408468_d9ed795f4f.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2709775832_85b4b50a57.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2717418782_bd83307d9f.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/272986700_d4d4bf8c4b.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2741763055_9a7bb00802.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2745389517_250a397f31.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2751836205_6f7b5eff30.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2782079948_8d4e94a826.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2809496124_5f25b5946a.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2815838190_0a9889d995.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2841437312_789699c740.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/2883093452_7e3a1eb53f.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/290082189_f66cb80bfc.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/296565463_d07a7bed96.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/3077452620_548c79fda0.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/348291597_ee836fbb1a.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/350436573_41f4ecb6c8.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/353266603_d3eac7e9a0.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/372228424_16da1f8884.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/400262091_701c00031c.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/416144384_961c326481.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/44105569_16720a960c.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/456097971_860949c4fc.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/464594019_1b24a28bb1.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/485743562_d8cc6b8f73.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/540976476_844950623f.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/54736755_c057723f64.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/57459255_752774f1b2.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/576452297_897023f002.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/586474709_ae436da045.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/590318879_68cf112861.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/59798110_2b6a3c8031.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/603709866_a97c7cfc72.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/603711658_4c8cd2201e.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/65038344_52a45d090d.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/6a00d8341c630a53ef00e553d0beb18834-800wi.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/72100438_73de9f17af.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/759745145_e8bc776ec8.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/936182217_c4caa5222d.jpg  \n",
      "  inflating: hymenoptera_data/val/bees/abeja.jpg  \n"
     ]
    }
   ],
   "source": [
    "# download the data\n",
    "!wget https://download.pytorch.org/tutorial/hymenoptera_data.zip\n",
    "!unzip hymenoptera_data.zip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data Transformation\n",
    "This is an image classification task, which means that we need to perform a few transformations on our dataset before we train our models. I used similar transformations as used in this [tutorial](https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html#transfer-learning-for-computer-vision-tutorial). For a detailed overview of each transformation take a look at the official torchvision [documentation](https://pytorch.org/docs/stable/torchvision/transforms.html).\n",
    "\n",
    "The following code block performs the following operations:\n",
    "- The `data_transforms` contains a series of transformations that will be performed on each image found in the dataset. This includes cropping the image, resizing the image, converting it to tensor, reshaping it, and normalizing it. \n",
    "- Once those transformations have been defined, then the `DataLoader` function is used to automatically load the datasets and perform any additional configuration such as shuffling, batches, etc."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# configure root folder on your gdrive\n",
    "data_dir = 'hymenoptera_data'\n",
    "\n",
    "# custom transformer to flatten the image tensors\n",
    "class ReshapeTransform:\n",
    "    def __init__(self, new_size):\n",
    "        self.new_size = new_size\n",
    "\n",
    "    def __call__(self, img):\n",
    "        result = torch.reshape(img, self.new_size)\n",
    "        return result\n",
    "\n",
    "# transformations used to standardize and normalize the datasets\n",
    "data_transforms = {\n",
    "    'train': transforms.Compose([\n",
    "        transforms.Resize(224),\n",
    "        transforms.CenterCrop(224),\n",
    "        transforms.ToTensor(),\n",
    "        ReshapeTransform((-1,)) # flattens the data\n",
    "    ]),\n",
    "    'val': transforms.Compose([\n",
    "        transforms.Resize(224),\n",
    "        transforms.CenterCrop(224),\n",
    "        transforms.ToTensor(),\n",
    "        ReshapeTransform((-1,)) # flattens the data\n",
    "    ]),\n",
    "}\n",
    "\n",
    "# load the correspoding folders\n",
    "image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),\n",
    "                                          data_transforms[x])\n",
    "                  for x in ['train', 'val']}\n",
    "\n",
    "# load the entire dataset; we are not using minibatches here\n",
    "train_dataset = torch.utils.data.DataLoader(image_datasets['train'],\n",
    "                                            batch_size=len(image_datasets['train']),\n",
    "                                            shuffle=True)\n",
    "\n",
    "test_dataset = torch.utils.data.DataLoader(image_datasets['val'],\n",
    "                                           batch_size=len(image_datasets['val']),\n",
    "                                           shuffle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(244, 153)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(image_datasets['train']), len(image_datasets['val'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Print sample\n",
    "It's always a good practise to take a quick look at the dataset before training your models. Below we print out an example of one of the images from the `train_dataset`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dimension of image: torch.Size([244, 150528]) \n",
      " Dimension of labels torch.Size([244])\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/codespace/.conda/envs/play/lib/python3.7/site-packages/ipykernel_launcher.py:9: UserWarning: The use of `x.T` on tensors of dimension other than 2 to reverse their shape is deprecated and it will throw an error in a future release. Consider `x.mT` to transpose batches of matricesor `x.permute(*torch.arange(x.ndim - 1, -1, -1))` to reverse the dimensions of a tensor. (Triggered internally at  /opt/conda/conda-bld/pytorch_1646755953518/work/aten/src/ATen/native/TensorShape.cpp:2318.)\n",
      "  if __name__ == '__main__':\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7faf586e2f10>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# load the entire dataset\n",
    "x, y = next(iter(train_dataset))\n",
    "\n",
    "# print one example\n",
    "dim = x.shape[1]\n",
    "print(\"Dimension of image:\", x.shape, \"\\n\", \n",
    "      \"Dimension of labels\", y.shape)\n",
    "\n",
    "plt.imshow(x[160].reshape(1, 3, 224, 224).squeeze().T.numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Building the Model\n",
    "Let's now implement our [logistic regression](https://en.wikipedia.org/wiki/Logistic_regression) model. Logistic regression is one in a family of machine learning techniques that are used to train binary classifiers. They are also a great way to understand the fundamental building blocks of neural networks, thus they can also be considered the simplest of neural networks where the model performs a `forward` and `backward` propagation to train the model on the data provided. \n",
    "\n",
    "If you don't fully understand the structure of the code below, I strongly recommend you to read the following [tutorial](https://medium.com/dair-ai/pytorch-1-2-introduction-guide-f6fa9bb7597c), which I wrote for PyTorch beginners. You can also check out [Week 2](https://www.coursera.org/learn/neural-networks-deep-learning/home/week/2) of Andrew Ng's Deep Learning Specialization course for all the explanation, intuitions, and details of the different parts of the neural network such as the `forward`, `sigmoid`, `backward`, and `optimization` steps. \n",
    "\n",
    "In short:\n",
    "- The `__init__` function initializes all the parameters (`W`, `b`, `grad`) that will be used to train the model through backpropagation. \n",
    "- The goal is to learn the `W` and `b` that minimimizes the cost function which is computed as seen in the `loss` function below.\n",
    "\n",
    "Note that this is a very detailed implementation of a logistic regression model so I had to explicitly move a lot of the computations into the GPU for faster calcuation, `to(device)` takes care of this in PyTorch. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class LR(nn.Module):\n",
    "    def __init__(self, dim, lr=torch.scalar_tensor(0.01)):\n",
    "        super(LR, self).__init__()\n",
    "        # intialize parameters\n",
    "        self.w = torch.zeros(dim, 1, dtype=torch.float).to(device)\n",
    "        self.b = torch.scalar_tensor(0).to(device)\n",
    "        self.grads = {\"dw\": torch.zeros(dim, 1, dtype=torch.float).to(device),\n",
    "                      \"db\": torch.scalar_tensor(0).to(device)}\n",
    "        self.lr = lr.to(device)\n",
    "\n",
    "    def forward(self, x):\n",
    "        # compute forward\n",
    "        z = torch.mm(self.w.T, x) + self.b\n",
    "        a = self.sigmoid(z)\n",
    "        return a\n",
    "\n",
    "    def sigmoid(self, z):\n",
    "        # compute sigmoid\n",
    "        return 1/(1 + torch.exp(-z))\n",
    "\n",
    "    def backward(self, x, yhat, y):\n",
    "        # compute backward\n",
    "        self.grads[\"dw\"] = (1/x.shape[1]) * torch.mm(x, (yhat - y).T)\n",
    "        self.grads[\"db\"] = (1/x.shape[1]) * torch.sum(yhat - y)\n",
    "    \n",
    "    def optimize(self):\n",
    "        # optimization step\n",
    "        self.w = self.w - self.lr * self.grads[\"dw\"]\n",
    "        self.b = self.b - self.lr * self.grads[\"db\"]\n",
    "\n",
    "## utility functions\n",
    "def loss(yhat, y):\n",
    "    m = y.size()[1]\n",
    "    return -(1/m)* torch.sum(y*torch.log(yhat) + (1 - y)* torch.log(1-yhat))\n",
    "\n",
    "def predict(yhat, y):\n",
    "    y_prediction = torch.zeros(1, y.size()[1])\n",
    "    for i in range(yhat.size()[1]):\n",
    "        if yhat[0, i] <= 0.5:\n",
    "            y_prediction[0, i] = 0\n",
    "        else:\n",
    "            y_prediction[0, i] = 1\n",
    "    return 100 - torch.mean(torch.abs(y_prediction - y)) * 100"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pretesting the Model\n",
    "It is also good practice to test your model and make sure the right steps are taking place before training the entire model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cost:  tensor(0.6931)\n",
      "Accuracy:  tensor(50.4098)\n"
     ]
    }
   ],
   "source": [
    "# model pretesting\n",
    "x, y = next(iter(train_dataset))\n",
    "\n",
    "# flatten/transform the data\n",
    "x_flatten = x.T\n",
    "y = y.unsqueeze(0) \n",
    "\n",
    "# num_px is the dimension of the images\n",
    "dim = x_flatten.shape[0]\n",
    "\n",
    "# model instance\n",
    "model = LR(dim)\n",
    "model.to(device)\n",
    "yhat = model.forward(x_flatten.to(device))\n",
    "yhat = yhat.data.cpu()\n",
    "\n",
    "# calculate loss\n",
    "cost = loss(yhat, y)\n",
    "prediction = predict(yhat, y)\n",
    "print(\"Cost: \", cost)\n",
    "print(\"Accuracy: \", prediction)\n",
    "\n",
    "# backpropagate\n",
    "model.backward(x_flatten.to(device), yhat.to(device), y.to(device))\n",
    "model.optimize()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train the Model\n",
    "It's now time to train the model. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cost after iteration 0: 0.6931472420692444 | Train Acc: 50.40983581542969 | Test Acc: 45.75163269042969\n",
      "Cost after iteration 10: 0.6691470742225647 | Train Acc: 64.3442611694336 | Test Acc: 54.24836730957031\n",
      "Cost after iteration 20: 0.6513182520866394 | Train Acc: 68.44261932373047 | Test Acc: 54.24836730957031\n",
      "Cost after iteration 30: 0.6367825865745544 | Train Acc: 68.03278350830078 | Test Acc: 54.24836730957031\n",
      "Cost after iteration 40: 0.6245337128639221 | Train Acc: 69.67213439941406 | Test Acc: 54.90196228027344\n",
      "Cost after iteration 50: 0.6139225959777832 | Train Acc: 70.90164184570312 | Test Acc: 56.20914840698242\n",
      "Cost after iteration 60: 0.6045235395431519 | Train Acc: 72.54098510742188 | Test Acc: 56.86274337768555\n",
      "Cost after iteration 70: 0.5960511565208435 | Train Acc: 74.18032836914062 | Test Acc: 57.51633834838867\n",
      "Cost after iteration 80: 0.5883085131645203 | Train Acc: 73.77049255371094 | Test Acc: 57.51633834838867\n",
      "Cost after iteration 90: 0.5811557769775391 | Train Acc: 74.59016418457031 | Test Acc: 58.1699333190918\n",
      "Cost after iteration 100: 0.5744912028312683 | Train Acc: 75.0 | Test Acc: 59.47712326049805\n",
      "Cost after iteration 110: 0.5682381987571716 | Train Acc: 75.40983581542969 | Test Acc: 60.13071823120117\n",
      "Cost after iteration 120: 0.5623382925987244 | Train Acc: 75.81967163085938 | Test Acc: 60.13071823120117\n",
      "Cost after iteration 130: 0.5567454099655151 | Train Acc: 75.81967163085938 | Test Acc: 59.47712326049805\n",
      "Cost after iteration 140: 0.5514224767684937 | Train Acc: 75.81967163085938 | Test Acc: 59.47712326049805\n",
      "Cost after iteration 150: 0.5463393926620483 | Train Acc: 76.22950744628906 | Test Acc: 58.82352828979492\n",
      "Cost after iteration 160: 0.5414712429046631 | Train Acc: 76.63934326171875 | Test Acc: 58.82352828979492\n",
      "Cost after iteration 170: 0.5367968678474426 | Train Acc: 77.04917907714844 | Test Acc: 58.82352828979492\n",
      "Cost after iteration 180: 0.5322986245155334 | Train Acc: 77.04917907714844 | Test Acc: 58.82352828979492\n",
      "Cost after iteration 190: 0.5279611349105835 | Train Acc: 77.45901489257812 | Test Acc: 58.82352828979492\n",
      "Cost after iteration 200: 0.5237710475921631 | Train Acc: 78.2786865234375 | Test Acc: 58.1699333190918\n",
      "Cost after iteration 210: 0.5197169184684753 | Train Acc: 78.2786865234375 | Test Acc: 58.1699333190918\n",
      "Cost after iteration 220: 0.5157885551452637 | Train Acc: 79.09835815429688 | Test Acc: 57.51633834838867\n",
      "Cost after iteration 230: 0.5119768977165222 | Train Acc: 79.91802978515625 | Test Acc: 57.51633834838867\n",
      "Cost after iteration 240: 0.5082740187644958 | Train Acc: 79.91802978515625 | Test Acc: 60.13071823120117\n",
      "Cost after iteration 250: 0.5046727657318115 | Train Acc: 79.91802978515625 | Test Acc: 60.13071823120117\n",
      "Cost after iteration 260: 0.5011667013168335 | Train Acc: 80.73770141601562 | Test Acc: 60.7843132019043\n",
      "Cost after iteration 270: 0.49775001406669617 | Train Acc: 81.14753723144531 | Test Acc: 60.7843132019043\n",
      "Cost after iteration 280: 0.49441757798194885 | Train Acc: 81.557373046875 | Test Acc: 60.7843132019043\n",
      "Cost after iteration 290: 0.49116453528404236 | Train Acc: 81.557373046875 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 300: 0.48798662424087524 | Train Acc: 81.557373046875 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 310: 0.48487982153892517 | Train Acc: 81.96721649169922 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 320: 0.4818406403064728 | Train Acc: 81.96721649169922 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 330: 0.4788656532764435 | Train Acc: 82.37704467773438 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 340: 0.4759517014026642 | Train Acc: 82.37704467773438 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 350: 0.4730961322784424 | Train Acc: 83.19672393798828 | Test Acc: 62.09150314331055\n",
      "Cost after iteration 360: 0.4702962040901184 | Train Acc: 84.01639556884766 | Test Acc: 62.09150314331055\n",
      "Cost after iteration 370: 0.46754947304725647 | Train Acc: 84.01639556884766 | Test Acc: 62.09150314331055\n",
      "Cost after iteration 380: 0.46485379338264465 | Train Acc: 84.01639556884766 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 390: 0.4622068703174591 | Train Acc: 84.01639556884766 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 400: 0.4596068263053894 | Train Acc: 84.01639556884766 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 410: 0.45705193281173706 | Train Acc: 84.01639556884766 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 420: 0.4545402526855469 | Train Acc: 84.42623138427734 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 430: 0.4520702660083771 | Train Acc: 84.83606719970703 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 440: 0.4496404826641083 | Train Acc: 84.83606719970703 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 450: 0.4472493827342987 | Train Acc: 85.24590301513672 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 460: 0.4448956549167633 | Train Acc: 85.6557388305664 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 470: 0.4425780475139618 | Train Acc: 85.6557388305664 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 480: 0.44029536843299866 | Train Acc: 85.6557388305664 | Test Acc: 61.43790817260742\n",
      "Cost after iteration 490: 0.43804648518562317 | Train Acc: 85.6557388305664 | Test Acc: 61.43790817260742\n"
     ]
    }
   ],
   "source": [
    "# hyperparams\n",
    "costs = []\n",
    "dim = x_flatten.shape[0]\n",
    "learning_rate = torch.scalar_tensor(0.0001).to(device)\n",
    "num_iterations = 500\n",
    "lrmodel = LR(dim, learning_rate)\n",
    "lrmodel.to(device)\n",
    "\n",
    "# transform the data\n",
    "def transform_data(x, y):\n",
    "    x_flatten = x.T\n",
    "    y = y.unsqueeze(0) \n",
    "    return x_flatten, y \n",
    "\n",
    "# train the model\n",
    "for i in range(num_iterations):\n",
    "    x, y = next(iter(train_dataset))\n",
    "    test_x, test_y = next(iter(test_dataset))\n",
    "    x, y = transform_data(x, y)\n",
    "    test_x, test_y = transform_data(test_x, test_y)\n",
    "\n",
    "    # forward\n",
    "    yhat = lrmodel.forward(x.to(device))\n",
    "    cost = loss(yhat.data.cpu(), y)\n",
    "    train_pred = predict(yhat, y)\n",
    "        \n",
    "    # backward\n",
    "    lrmodel.backward(x.to(device), \n",
    "                    yhat.to(device), \n",
    "                    y.to(device))\n",
    "    lrmodel.optimize()\n",
    "\n",
    "    # test\n",
    "    yhat_test = lrmodel.forward(test_x.to(device))\n",
    "    test_pred = predict(yhat_test, test_y)\n",
    "\n",
    "    if i % 10 == 0:\n",
    "        costs.append(cost)\n",
    "\n",
    "    if i % 10 == 0:\n",
    "        print(\"Cost after iteration {}: {} | Train Acc: {} | Test Acc: {}\".format(i, \n",
    "                                                                                    cost, \n",
    "                                                                                    train_pred,\n",
    "                                                                                    test_pred))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Result\n",
    "From the loss curve below you can see that the model is sort of learning to classify the images given the decreas in the loss. I only ran the model for `100` iterations. Train the model for many more rounds and analyze the results. In fact, I have suggested a couple of experiments and exercises at the end of the tutorial that you can try to get a more improved model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "## the trend in the context of loss\n",
    "plt.plot(costs)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Some Notes\n",
    "There are many improvements and different experiments that you can perform on top of this notebook to keep practising ML:\n",
    "- It is always good to normalize/standardize your images which helps with learning. As an experiment, you can research and try different ways to standarize the dataset. We have normalized the dataset with the builtin PyTorch [normalizer](https://pytorch.org/docs/stable/torchvision/transforms.html#torchvision.transforms.Normalize) which uses the mean and standard deviation. Play around with different transformations or normalization techniques. What effect does this have on learning in terms of speed and loss?\n",
    "- You can try many things to help with learning such as playing around with the learning rate. Try to decrease and increase the learning rate and observe the effect of this in learning? \n",
    "- If you explored the dataset further, you may have noticed that all the \"no-bee\" images are actually \"ant\" images. If you would like to create a more robust model, you may want to make your \"no-bee\" images more random and diverse through some data augmentation technique. This is a more advanced approach but there is a lot of good content to try out this idea. \n",
    "- The model is not really performing well just using simple logistic regression model. It could be because of the dataset I am using and because I didn't train it for long enough. Hyperparameters may also be off. It is a relatively small dataset but the performance could get better with more data and training over time. A more challenging task involves adopting the model to other datasets. Give it a try!\n",
    "- Another important part that is missing in this tutorial is the comprehensive analysis of the model results. If you understand the code, it should be easy to figure out how to test with a few examples. In fact, it would also be great if you can put aside a small testing dataset for this part of the exercise, so as to test the generalization capabilities of the model.\n",
    "- We built the logistic regression model from scratch but with libraries like PyTorch, these days you can simply leverage the high-level functions that implement certain parts of the neural network for you. This simplifies your code and minimizes the amount of bugs in your code. Plus you don't have to code your neural networks from scratch all the time. As a bonus exercise, try to adapt PyTorch builtin modules and functions for implementing a simpler, more concise version of the above logistic regression model. I will also add this as a to-do task for myself and post a solution soon. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References\n",
    "- [Understanding the Impact of Learning Rate on Neural Network Performance](https://machinelearningmastery.com/understand-the-dynamics-of-learning-rate-on-deep-learning-neural-networks/)\n",
    "- [Transfer Learning for Computer Vision Tutorial](https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html#transfer-learning-for-computer-vision-tutorial)\n",
    "- [Deep Learning Specialization by Andrew Ng](https://www.coursera.org/learn/neural-networks-deep-learning/home/welcome)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.7.13 ('play')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.13"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "cf9800998463bc980d70cdbacff0c7e9a10687346dc898569e92f016d6e252c9"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
